<!--
 * @Author: rxn 1003312535@qq.com
 * @Date: 2024-07-05 15:25:53
 * @LastEditors: rxn 1003312535@qq.com
 * @LastEditTime: 2024-08-07 10:14:18
 * @FilePath: \vue3-progect\src\views\example\three\geometry\index.vue
 * @Description: 管道漫游
-->
<!--相机基础-->
<template>
	<div id="three_container"></div>
</template>

<script setup>
import * as THREE from "three";
import { onMounted } from "vue";
//-引入后处理扩展库EffectComposer.js
import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
//-引入渲染器通道RenderPass
import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
//-引入OutlinePass通道,给指定的某个模型对象添加一个高亮发光描边效果
import { OutlinePass } from "three/addons/postprocessing/OutlinePass.js";
//-引入UnrealBloomPass通道
import { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js";
//-引入GlitchPass通道,GlitchPass通道会产生闪屏效果。
import { GlitchPass } from "three/addons/postprocessing/GlitchPass.js";
//-
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
let scene, renderer, camera, controls, container, composer;
onMounted(() => {
	container = document.getElementById("three_container");
	scene = new THREE.Scene();
	// 正投影相机
	const width = container.offsetWidth; //canvas画布宽度
	const height = container.offsetHeight; //canvas画布高度
	const k = width / height; //canvas画布宽高比
	const s = 200; //控制left, right, top, bottom范围大小
	camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 11000);
	camera.position.set(0, 0, 200); //设置相机位置
	// camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
	// camera = createCamera(THREE, container);

	//--
	renderer = new THREE.WebGLRenderer({
		antialias: true
	});
	renderer.setSize(container.offsetWidth, container.offsetHeight);
	container.appendChild(renderer.domElement);
	renderer.render(scene, camera);

	//--
	controls = new OrbitControls(camera, renderer.domElement);
	controls.update();
	//--
	const axesHelper = new THREE.AxesHelper(800);
	scene.add(axesHelper);
	//--
	const ambient = new THREE.AmbientLight("#ffffff");
	scene.add(ambient);

	// 画布跟随窗口变化
	window.onresize = function () {
		const width = container.offsetWidth;
		const height = container.offsetHeight;
		renderer.setSize(width, height);
		camera.aspect = width / height;
		camera.updateProjectionMatrix();
	};
	// demo();
	demo1();
	demo2();
	demo3();
	animate(renderer, scene, camera);
});
const animate = (renderer, scene, camera) => {
	composer.render();
	requestAnimationFrame(animate.bind(this, renderer, scene, camera));
	// renderer.render(scene, camera);
};

const demo3 = () => {
	let { outlinePass, bloomPass } = dome();
	renderer.domElement.addEventListener("click", function (event) {
		// .offsetY、.offsetX以canvas画布左上角为坐标原点,单位px
		const px = event.offsetX;
		const py = event.offsetY;
		const x = (px / container.offsetWidth) * 2 - 1;
		const y = -(py / container.offsetHeight) * 2 + 1;
		console.log("offsetX:", px, "offsetY:", py);
		console.log(scene);
		const raycaster = new THREE.Raycaster();
		raycaster.setFromCamera(new THREE.Vector2(x, y), camera);
		const intersects = raycaster.intersectObjects(scene.children, true);
		let arr = [];
		for (let i = 0; i < intersects.length; i++) {
			arr.push(intersects[i].object);
		}
		console.log("射线穿过的接口：", arr);
		outlinePass.selectedObjects = arr;
		// 设置OutlinePass通道
		// composer.addPass(bloomPass);
	});
};
/**
 * 射线
 * 一条线把一个点作为起点，然后沿着某个方向无限延伸。
 */
const demo2 = () => {
	const geometry = new THREE.SphereGeometry(25, 50, 50);
	const material = new THREE.MeshLambertMaterial({
		color: 0x009999
	});
	const mesh1 = new THREE.Mesh(geometry, material);
	const mesh2 = mesh1.clone();
	mesh2.position.y = 100;
	const mesh3 = mesh1.clone();
	mesh3.position.x = 100;
	const model = new THREE.Group();
	// 三个网格模型mesh1,mesh2,mesh3用于射线拾取测试
	model.add(mesh1, mesh2, mesh3);
	// 注意更新下模型的世界矩阵，你设置的mesh.position生效，再进行射线拾取计算
	// 不更新不起作用，射线回拿到所有 mesh
	//注意更新下模型的世界矩阵，你设置的position生效，再进行射线拾取计算
	model.updateMatrixWorld(true);
	scene.add(model);

	const boxGeometry = new THREE.BoxGeometry(10, 10, 10);
	const boxMesh = new THREE.Mesh(boxGeometry, material);
	boxMesh.position.x = -50;
	scene.add(boxMesh);
	/**
	 * --射线投射器Raycaster
	 */
	const raycaster = new THREE.Raycaster();
	// 设置射线起点
	raycaster.ray.origin = new THREE.Vector3(-100, 0, 0);
	// 设置射线方向射线方向沿着x轴
	raycaster.ray.direction = new THREE.Vector3(1, 0, 0);
	// 射线发射拾取模型对象
	const intersects = raycaster.intersectObjects([mesh1, mesh2, mesh3]);
	console.log("射线器返回的对象", intersects);
	if (intersects.length > 0) {
		// 选中模型的第一个模型，设置为红色
		intersects[0].object.material.color.set(0xff0000);
	}
};
const demo1 = () => {
	const ray = new THREE.Ray();
	console.log(ray, "ray");
	//-射线七点
	ray.origin.set(1, 1, 1);
	//-射线方向,注意.direction的值需要是单位向量
	ray.direction = new THREE.Vector3(0, 0, 1);
	ray.direction = new THREE.Vector3(11, 0, 0).normalize();

	/**
	 *
	 */
	// 三角形三个点坐标
	const p1 = new THREE.Vector3(100, 25, 0);
	const p2 = new THREE.Vector3(100, -25, 25);
	const p3 = new THREE.Vector3(100, -25, -25);
	const point = new THREE.Vector3(); //用来记录射线和三角形的交叉点
	// `.intersectTriangle()`计算射线和三角形是否相交叉，相交返回交点，不相交返回null
	//参数4表示是否进行背面剔除
	//
	const result = ray.intersectTriangle(p1, p2, p3, false, point);
	console.log("交叉点坐标", point);
	console.log("查看是否相交", result);
};

const dome = () => {
	composer = new EffectComposer(renderer);
	const renderPass = new RenderPass(scene, camera);
	composer.addPass(renderPass);
	const v2 = new THREE.Vector2(container.offsetWidth, container.offsetHeight);
	const outlinePass = new OutlinePass(v2, scene, camera);
	//模型描边颜色，默认白色
	outlinePass.visibleEdgeColor.set(0xffff00);
	//高亮发光描边厚度
	outlinePass.edgeThickness = 4;
	//高亮描边发光强度
	outlinePass.edgeStrength = 6;
	//模型闪烁频率控制，默认0不闪烁
	outlinePass.pulsePeriod = 2;
	// 设置OutlinePass通道
	composer.addPass(outlinePass);
	// canvas画布宽高度尺寸是800, 600
	const bloomPass = new UnrealBloomPass(
		new THREE.Vector2(container.offsetWidth, container.offsetHeight)
	);
	//bloom发光强度
	bloomPass.strength = 2.0;
	// /**
	//  * GlitchPass通道会产生闪屏效果。
	//  */
	// const glitchPass = new GlitchPass();
	// // 设置glitchPass通道
	// composer.addPass(glitchPass);
	return {
		outlinePass,
		bloomPass
	};
};
</script>

<style lang="less" scoped>
#three_container {
	height: 100%;
}
.downLoadBtn {
	position: absolute;
	right: 0;
	top: 10px;
	z-index: 99;
}
</style>
